#include <stdio.h>

/*

我们通过对快排函数参数的理解,来写一个能够排序任何数据的冒泡排序

void qsort 
(
    void* array ,
    size_t num ,
    size_t size ,
    int (*cmpar) (const void* p1 , const void* p2)
)

*/

// 我们学到的冒泡函数的不足之处: 只能处理整型数据
// 既然我们学了快排,我们发现: 快排里面的数据不论什么什么类型都是可以排序的,实现的基础是把比较的函数交给了程序员去写
// 除了比较是自己写之外,但是交换这一些是快排里面实现的,所以快排适用于很多的类型

/*

对照快排,我们将快排的参数写入我们自己的冒泡排序对照一下

void bubble_sort 
(
    void* array
    size_t sz
    size_t size
    int (*cmp) (const void* p1 , const void* p2)
)

我们可以发现,一个基本的排序只需要满足,比较,交换就可以了
那比较怎么解决呢？
我们只能根据数据内容进行比较,没有办法用一个完美的解决方法去通用所有的数据类型

那排序呢？
排序就比较简单了,因为排序根据元素的大小,以字节为单位去交换元素的大小次字节就可以完成一整个的交换
所以我们来找猫画虎地试一下怎么写

*/

int cmp_int (const void* p1 , const void* p2) // 这里和快排一样,使用了函数指针,可以方便在函数内调用 同时根据数据类型比较
{

    return *(int*) p1 - *(int*) p2 ;

}

void swap (char* p1 , char* p2 , int size) // 交换函数,特点在于使用了char类型,可以一个字节一个字节地交换,根据不同数据类型大小交换不同大小的字节
{

    for (int i = 0 ; i < size ; i++) // 什么数据类型就循环交换多少次字节 里面的变量全部为解引用之后的值
    {

        char tmp = p1 [i] ;

        p1 [i] = p2 [i] ;

        p2 [i] = tmp ;

    } // 这里同样可以用异或解决,但是可能在效率上会慢于设立临时值保存

}

void bubble_sort (void* array , size_t sz , size_t size , int (*cmp) (const void* , const void*))
{

    for (int j = 0 ; j < sz ; j++)
    {

        for (int k = 0 ; k < sz - j - 1 ; k++)
        {

            if (cmp ((char*) array + k * size , (char*) array + (k + 1) * size) > 0) // 这里的判断函数修改大小就可以实现升序或者降序排列
            {

                swap (array + k * size , array + (k + 1) * size , size) ;

            }

        }

    }

}

int main ()
{

    int array [] = {1 , 3 , 5 , 7 , 9 , 2 , 4 , 6 , 8 , 10} ;

    size_t sz = sizeof (array) / sizeof (array [0]) ;

    bubble_sort (array , sz , sizeof (array [0]) , cmp_int) ;

    for (int i = 0 ; i < sz ; i++)
    {

        printf ("%d " , array [i]) ;

    }

    return 0 ;

}